import 'dart:io';

import 'package:barcode/assets_image_list_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_ml_kit/google_ml_kit.dart';
import 'package:image_picker/image_picker.dart';
import 'package:oktoast/oktoast.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return OKToast(
      backgroundColor: Colors.black54,
      textPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
      radius: 20.0,
      position: ToastPosition.center,
      child: MaterialApp(
        title: 'Barcode Scanner',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String assetsBarcodePath = '';
  String assetsQrcodePath = '';

  final ImagePicker _picker = ImagePicker();
  XFile? pickedFile;

  String? path;
  String? barcode;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
      assetsBarcodePath = await getAssetFilePath('barcode.png');
      assetsQrcodePath = await getAssetFilePath('qr_code.png');
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('barcode'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              const SizedBox(height: 20),

              if (path != null)
                Image.file(
                  File(path!),
                  width: 200,
                  height: 200,
                  fit: BoxFit.fill,
                ),
              const SizedBox(
                height: 20,
              ),
              FilledButton(
                  onPressed: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (_) => AssetsImageListPage(
                                  assetsBarcodePath: assetsBarcodePath,
                                  assetsQrcodePath: assetsQrcodePath,
                                  onSelectCallBack: (String value) {
                                    clearAllPath();
                                    path = value;
                                    scanBarcode();
                                  },
                                )));
                  },
                  child: const Text('From Assets')),
              const SizedBox(height: 10),
              FilledButton(
                  onPressed: () {
                    getImageByGallery();
                  },
                  child: const Text('From Gallery')),
              const SizedBox(height: 10),
              FilledButton(
                  onPressed: () {
                    getImageByCamera();
                  },
                  child: const Text('Take a picture')),
              Padding(
                padding: const EdgeInsets.all(16),
                child:
                    Row(mainAxisAlignment: MainAxisAlignment.start, children: [
                  Expanded(child: Text('Image path: ${path ?? ''}')),
                ]),
              ),
              Padding(
                padding: const EdgeInsets.all(16),
                child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      Expanded(child: Text('Barcode: ${barcode ?? ''}'))
                    ]),
              ),
            ],
          ),
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  void clearAllPath() {
    path = null;
    barcode = null;
  }

  Future<void> getImageByGallery() async {
    try {
      pickedFile =
          await _picker.pickImage(source: ImageSource.gallery, maxWidth: 800);

      clearAllPath();
      path = pickedFile?.path;
      scanBarcode();
    } catch (e) {
      if (e is MissingPluginException) {
        Toast.show('The current platform does not support it！');
      } else {
        Toast.show("Can't open album without permission!");
      }
    }
  }

  Future<void> getImageByCamera() async {
    try {
      pickedFile =
          await _picker.pickImage(source: ImageSource.camera, maxWidth: 800);
      clearAllPath();
      path = pickedFile?.path;
      scanBarcode();
    } catch (e) {
      if (e is MissingPluginException) {
        Toast.show('The current platform does not support it！');
      } else {
        Toast.show("Can't open camera without permission!");
      }
    }
  }

  Future<String> getTemporaryDirectoryPath() async {
    final directory = await getTemporaryDirectory();
    return directory.path;
  }

  Future<File> copyAssetToFile(String assetName, String targetPath) async {
    // 检查文件是否已经存在
    final file = File(targetPath);
    if (!await file.exists()) {
      // 加载资源文件
      final data = await rootBundle.load(assetName);
      final bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      // 写入文件
      return file.writeAsBytes(bytes);
    }
    return file;
  }

  Future<String> getAssetFilePath(String assetName) async {
    // 获取临时目录路径
    final tempDirPath = await getTemporaryDirectoryPath();
    // 构建目标文件路径
    final targetPath = '$tempDirPath/$assetName';
    // 确保文件名没有前导斜杠
    if (assetName.startsWith('/')) {
      assetName = assetName.substring(1);
    }
    // 复制资源文件到临时目录
    await copyAssetToFile('assets/$assetName', targetPath);
    return targetPath;
  }

  void scanBarcode() async {
    BarcodeScanner barcodeScanner = BarcodeScanner();

    final List<Barcode> barcodes =
        await barcodeScanner.processImage(InputImage.fromFile(File(path!)));

    if (barcodes.isNotEmpty) {
      barcode = barcodes[0].rawValue;
      Toast.show('Scanning successful');
    } else {
      Toast.show('No barcode found');
    }
    setState(() {});
  }
}

class Toast {
  static void show(String? msg, {int duration = 2000}) {
    if (msg == null) {
      return;
    }
    showToast(msg,
        duration: Duration(milliseconds: duration),
        dismissOtherToast: true,
        position: ToastPosition.center);
  }

  static void showToastWithWidget(Widget? widget,
      {int duration = 2000, BuildContext? context}) {
    if (widget == null) {
      return;
    }
    showToastWidget(
      widget,
      duration: Duration(milliseconds: duration),
      dismissOtherToast: true,
      position: ToastPosition.center,
    );
  }

  static void cancelToast() {
    dismissAllToast();
  }
}
